/*
 * Copyright (C) 2012 Santiago Valdarrama
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package com.yuanmei.stockeyes;

import static com.yuanmei.stockeyes.artifacts.Extensions.fromStringToFloat;

import java.io.BufferedReader;
//import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;

/*
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
*/

//import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.util.Log;
import android.net.TrafficStats;

import com.yuanmei.stockeyes.artifacts.Constants;
import com.yuanmei.stockeyes.artifacts.Extensions;
import com.yuanmei.stockeyes.artifacts.GlobalSettings;
import com.yuanmei.stockeyes.data.DataProvider;
import com.yuanmei.stockeyes.receivers.ConnectivityBroadcastReceiver;

public class MarketCollectorService extends IntentService {

    private final static String LOG_TAG = "MarketCollectService";

    public final static String EXTRA_TICKER = "ticker";
    public final static String EXTRA_HIS_QUOTES = "his_quotes";

    // private final static String FIELD_CODE = "code";
    // private final static String FIELD_NAME = "name";
    // private final static String FIELD_MARKET = "type";
    private final static String FIELD_CHANGE_PERCENTAGE = "percent";
    private final static String FIELD_CHANGE = "updown";
    private final static String FIELD_PRICE = "price";
    private final static String FIELD_OPEN = "open";
    private final static String FIELD_LOW = "low";
    private final static String FIELD_HIGH = "high";
    private final static String FIELD_YEST_CLOSE = "yestclose";
    private final static String FIELD_VOLUME = "volume";
    private final static String FIELD_TURNOVER = "turnover";

    private final static String FIELD_BID5 = "bid5";
    private final static String FIELD_BIDVOL5 = "bidvol5";
    private final static String FIELD_BID4 = "bid4";
    private final static String FIELD_BIDVOL4 = "bidvol4";
    private final static String FIELD_BID3 = "bid3";
    private final static String FIELD_BIDVOL3 = "bidvol3";
    private final static String FIELD_BID2 = "bid2";
    private final static String FIELD_BIDVOL2 = "bidvol2";
    private final static String FIELD_BID1 = "bid1";
    private final static String FIELD_BIDVOL1 = "bidvol1";
    private final static String FIELD_ASK1 = "ask1";
    private final static String FIELD_ASKVOL1 = "askvol1";
    private final static String FIELD_ASK2 = "ask2";
    private final static String FIELD_ASKVOL2 = "askvol2";
    private final static String FIELD_ASK3 = "ask3";
    private final static String FIELD_ASKVOL3 = "askvol3";
    private final static String FIELD_ASK4 = "ask4";
    private final static String FIELD_ASKVOL4 = "askvol4";
    private final static String FIELD_ASK5 = "ask5";
    private final static String FIELD_ASKVOL5 = "askvol5";
    private final static String FIELD_UPDATE = "update";

    private static long sQuoteRecvBytes = 0;
    private static long sQuoteRecvCnts = 0;

    public MarketCollectorService() {
        super("Collector Service");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        SharedPreferences sharedPreferences = getSharedPreferences(
                Constants.PREFERENCES, Context.MODE_PRIVATE);
        long lastUpdate = sharedPreferences.getLong(
                Constants.PREFERENCE_COLLECTOR_LAST_UPDATE, 0);
        boolean retrying = sharedPreferences.getBoolean(
                Constants.PREFERENCE_COLLECTOR_RETRYING, false);
        boolean refresh = sharedPreferences.getBoolean(
                Constants.PREFERENCE_COLLECTOR_REFRESH, false);
        int retries = sharedPreferences.getInt(
                Constants.PREFERENCE_COLLECTOR_RETRIES, 0);
        boolean wereWeWaitingForConnectivity = sharedPreferences.getBoolean(
                Constants.PREFERENCE_STATUS_WAITING_FOR_CONNECTIVITY, false);

        boolean isGlobalCollection = intent.getExtras() == null
                || (intent.getExtras() != null && !intent.getExtras()
                        .containsKey(EXTRA_TICKER));

        // boolean isAutoMatic =
        // sharedPreferences.getBoolean(Constants.PREFERENCE_COLLECTOR_AUTOMATIC,
        // false);
        if (wereWeWaitingForConnectivity) {
            Editor editor = sharedPreferences.edit();
            editor.putBoolean(
                    Constants.PREFERENCE_STATUS_WAITING_FOR_CONNECTIVITY, false);
            editor.commit();
        }

        if (retrying && isGlobalCollection) {
            Editor editor = sharedPreferences.edit();
            editor.putBoolean(Constants.PREFERENCE_COLLECTOR_RETRYING, false);
            editor.putInt(Constants.PREFERENCE_COLLECTOR_RETRIES, 0);
            editor.commit();

            ((AlarmManager) getSystemService(Context.ALARM_SERVICE))
                    .cancel(Extensions.createPendingIntent(this,
                            Constants.SCHEDULE_RETRY));
        }

        long currentTime = System.currentTimeMillis();
        if (refresh
                || retrying
                || wereWeWaitingForConnectivity
                || (!isGlobalCollection)
                || (isGlobalCollection && currentTime - lastUpdate > GlobalSettings.slCurrentRefreshInterval)) {
            String[] tickers = null;

            if (isGlobalCollection) {
                Log.d(LOG_TAG,
                        "Executing global market information collection...");
                tickers = DataProvider.getStockDataTickers(this);
            } else {
                String ticker = intent.getExtras().containsKey(EXTRA_TICKER) ? intent
                        .getExtras().getString(EXTRA_TICKER) : null;

                Log.d(LOG_TAG,
                        "Executing market information collection for ticker "
                                + ticker + ".");

                tickers = new String[] { ticker };
            }

            try {
                collect(tickers);

                if (isGlobalCollection) {
                    Editor editor = sharedPreferences.edit();
                    editor.putLong(Constants.PREFERENCE_COLLECTOR_LAST_UPDATE,
                            System.currentTimeMillis());
                    editor.commit();
                }

                DataProvider.notifyDataCollectionIsFinished(this, tickers);

                if (isGlobalCollection
                        && GlobalSettings.sbIsOnSmartWatch
                        && (currentTime - lastUpdate > GlobalSettings.slCurrentRefreshInterval)) {
                    try {
                        DataProvider.checkStocksAndNotify(this, tickers);
                        Log.d(LOG_TAG, "Executing checkStockStatus Success");
                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.e(LOG_TAG, "Executing checkStockStatus exception: "
                                + e.toString());
                    }
                }
            } catch (Exception e) {
                Log.e(LOG_TAG, "Market information collection failed.", e);

                if (Extensions.areWeOnline(this)) {
                    Log.d(LOG_TAG,
                            "Scheduling an alarm for retrying a global market information collection...");

                    retries++;

                    Editor editor = sharedPreferences.edit();
                    editor.putBoolean(Constants.PREFERENCE_COLLECTOR_RETRYING,
                            true);
                    editor.putInt(Constants.PREFERENCE_COLLECTOR_RETRIES,
                            retries);
                    editor.commit();

                    long interval = Constants.COLLECTOR_MIN_RETRY_INTERVAL
                            * retries;
                    if (interval > Constants.COLLECTOR_MAX_REFRESH_INTERVAL) {
                        interval = Constants.COLLECTOR_MAX_REFRESH_INTERVAL;
                    }

                    ((AlarmManager) getSystemService(Context.ALARM_SERVICE))
                            .set(AlarmManager.RTC, System.currentTimeMillis()
                                    + interval, Extensions.createPendingIntent(
                                    this, Constants.SCHEDULE_RETRY));
                } else {
                    Log.d(LOG_TAG,
                            "It appears that we are not online, so let's start listening for connectivity updates.");

                    Editor editor = sharedPreferences.edit();
                    editor.putBoolean(
                            Constants.PREFERENCE_STATUS_WAITING_FOR_CONNECTIVITY,
                            true);
                    editor.commit();

                    ComponentName componentName = new ComponentName(this,
                            ConnectivityBroadcastReceiver.class);
                    getPackageManager().setComponentEnabledSetting(
                            componentName,
                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                            PackageManager.DONT_KILL_APP);
                }
            }
        } else if (isGlobalCollection
                && currentTime - lastUpdate <= GlobalSettings.slCurrentRefreshInterval) {
            Log.d(LOG_TAG,
                    "Global market information collection will be skipped since it was performed less than "
                            + (GlobalSettings.slCurrentRefreshInterval / 60 / 1000)
                            + " minutes ago.");
        }

        if ((null != GlobalSettings.scDashBoardActivityContext)
                && (GlobalSettings.slCurrentRefreshInterval != GlobalSettings.slSettingRefreshInterval)) {
            PendingIntent pendIntent = Extensions.createPendingIntent(
                    GlobalSettings.scDashBoardActivityContext,
                    Constants.SCHEDULE_AUTOMATIC);
            ((AlarmManager) getSystemService(Context.ALARM_SERVICE))
                    .cancel(pendIntent);
            Log.d(LOG_TAG,
                    "dashboard SCHEDULE_AUTOMATIC Interval Change from  "
                            + GlobalSettings.slCurrentRefreshInterval
                            / Constants.MINUTES_TO_MILLISECONDS + " min to "
                            + GlobalSettings.slSettingRefreshInterval
                            / Constants.MINUTES_TO_MILLISECONDS + " min");
            GlobalSettings.slCurrentRefreshInterval = GlobalSettings.slSettingRefreshInterval;
            ((AlarmManager) getSystemService(Context.ALARM_SERVICE))
                    .setInexactRepeating(AlarmManager.RTC, currentTime
                            + GlobalSettings.slCurrentRefreshInterval,
                            GlobalSettings.slCurrentRefreshInterval, pendIntent);
        }
        stopSelf();
    }

    private void collect(String[] tickers) throws Exception {
        long oldTotalBytes = TrafficStats.getTotalRxBytes();
        if (tickers.length > 0) {
            /*
            String response = "";
            DefaultHttpClient client = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet();
            HttpResponse execute = client.execute(httpGet);
            InputStream content = execute.getEntity().getContent();
                        BufferedReader buffer = new BufferedReader(new InputStreamReader(
                    content));
            String s = "";
            while ((s = buffer.readLine()) != null) {
                response += s;
            }
            */
            String req_url = createRESTServiceURL(tickers);
            String response = Extensions.getJSONFromUrl(req_url, 300 * 1000);

            int IdxLftQte = response.indexOf("(");
            int IdxRhtQte = response.indexOf(")");
            response = response.substring(IdxLftQte + 1, IdxRhtQte);
            JSONTokener json = new JSONTokener(response);
            if (json != null) {
                JSONObject rootJSONObject = (JSONObject) json.nextValue();

                for (int i = 0; i < tickers.length; i++) {
                    String stk_code = tickers[i];
                    if (stk_code.startsWith("^"))
                        stk_code = stk_code.substring(1);

                    if (stk_code.startsWith("sh")) {
                        stk_code = stk_code.substring(2);
                        stk_code = "0" + stk_code;
                    } else if (stk_code.startsWith("sz")) {
                        stk_code = stk_code.substring(2);
                        stk_code = "1" + stk_code;
                    }
                    JSONObject queryJSONObject = (JSONObject) rootJSONObject
                            .get(stk_code);
                    processJSON(tickers[i], queryJSONObject);
                }
            }
        }

        sQuoteRecvBytes += (TrafficStats.getTotalRxBytes() - oldTotalBytes);
        sQuoteRecvCnts += 1;
        Log.d(LOG_TAG, "sQuoteRecvBytes = " + sQuoteRecvBytes
                + " sQuoteRecvCnts=" + sQuoteRecvCnts);
    }

    private void processJSON(String ticker, JSONObject object)
            throws JSONException {
        // String code = object.getString(FIELD_CODE);
        // String name = object.getString(FIELD_NAME);
        Float changePercentage = fromStringToFloat(object
                .getString(FIELD_CHANGE_PERCENTAGE));
        Float change = fromStringToFloat(object.getString(FIELD_CHANGE));
        Float price = fromStringToFloat(object.getString(FIELD_PRICE));
        Float open = fromStringToFloat(object.getString(FIELD_OPEN));
        Float low = fromStringToFloat(object.getString(FIELD_LOW));
        Float high = fromStringToFloat(object.getString(FIELD_HIGH));
        Float yestClose = fromStringToFloat(object.getString(FIELD_YEST_CLOSE));
        Float volume = fromStringToFloat(object.getString(FIELD_VOLUME));
        Float turnover = fromStringToFloat(object.getString(FIELD_TURNOVER));
        Float bid5 = fromStringToFloat(object.getString(FIELD_BID5));
        Float bidvol5 = fromStringToFloat(object.getString(FIELD_BIDVOL5));
        Float bid4 = fromStringToFloat(object.getString(FIELD_BID4));
        Float bidvol4 = fromStringToFloat(object.getString(FIELD_BIDVOL4));
        Float bid3 = fromStringToFloat(object.getString(FIELD_BID3));
        Float bidvol3 = fromStringToFloat(object.getString(FIELD_BIDVOL3));
        Float bid2 = fromStringToFloat(object.getString(FIELD_BID2));
        Float bidvol2 = fromStringToFloat(object.getString(FIELD_BIDVOL2));
        Float bid1 = fromStringToFloat(object.getString(FIELD_BID1));
        Float bidvol1 = fromStringToFloat(object.getString(FIELD_BIDVOL1));

        Float ask1 = fromStringToFloat(object.getString(FIELD_ASK1));
        Float askvol1 = fromStringToFloat(object.getString(FIELD_ASKVOL1));
        Float ask2 = fromStringToFloat(object.getString(FIELD_ASK2));
        Float askvol2 = fromStringToFloat(object.getString(FIELD_ASKVOL2));
        Float ask3 = fromStringToFloat(object.getString(FIELD_ASK3));
        Float askvol3 = fromStringToFloat(object.getString(FIELD_ASKVOL3));
        Float ask4 = fromStringToFloat(object.getString(FIELD_ASK4));
        Float askvol4 = fromStringToFloat(object.getString(FIELD_ASKVOL4));
        Float ask5 = fromStringToFloat(object.getString(FIELD_ASK5));
        Float askvol5 = fromStringToFloat(object.getString(FIELD_ASKVOL5));

        String update = object.getString(FIELD_UPDATE);

        DataProvider.updateStockData(this, ticker, changePercentage, change,
                price, open, low, high, yestClose, volume, turnover, bid5,
                bidvol5, bid4, bidvol4, bid3, bidvol3, bid2, bidvol2, bid1,
                bidvol1, ask1, askvol1, ask2, askvol2, ask3, askvol3, ask4,
                askvol4, ask5, askvol5, update);

        long currentTime = System.currentTimeMillis();
        long lastUpdate = getSharedPreferences(Constants.PREFERENCES,
                Context.MODE_PRIVATE).getLong(
                Constants.PREFERENCE_COLLECTOR_LAST_UPDATE, 0);
        long diff = currentTime - lastUpdate;

        if (diff > GlobalSettings.slCurrentRefreshInterval) {
            long dateBigInt = Extensions.formatDateStringToDateLong(update);
            if (dateBigInt > 0) {
                DataProvider.updateTimeData(this, ticker, dateBigInt, price,
                        volume, turnover);
            }
        }
    }

    private String createRESTServiceURL(String[] tickers) {
        StringBuilder stringBuilder = new StringBuilder();

        stringBuilder.append("http://api.money.126.net/data/feed/");

        for (int i = 0; i < tickers.length; i++) {
            String stk_code = tickers[i];
            if (stk_code.startsWith("^"))
                stk_code = stk_code.substring(1);

            if (stk_code.startsWith("sh")) {
                stk_code = stk_code.substring(2);
                stringBuilder.append("0").append(stk_code).append("%2C");
            } else if (stk_code.startsWith("sz")) {
                stk_code = stk_code.substring(2);
                stringBuilder.append("1").append(stk_code).append("%2C");
            }
        }

        stringBuilder.append("money.api");

        return stringBuilder.toString();
    }

}
